﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

namespace Sofire.DataComm.Net
{
    /// <summary>
    /// 一个可靠套接字的服务端实现。
    /// </summary>
    public class SocketServer : SocketBase
    {
        private AsyncCallback BeginAcceptCallback;

        /// <summary>
        /// 接受一个传入的连接后发生。
        /// </summary>
        public event SocketEventHandler Accepted;
        /// <summary>
        /// 一个传入的连接断开后发生。
        /// </summary>
        public event SocketEventHandler Rejected;
        /// <summary>
        /// 当接入的连接抛出异常后发生。
        /// </summary>
        public event ExceptionEventHandler AcceptedFaild;

        private int _ListenBacklog = 10240;
        /// <summary>
        /// 设置或获取一个值，表示挂起连接队列的最大长度。
        /// </summary>
        public int ListenBacklog
        {
            get
            {
                return this._ListenBacklog;
            }
            set
            {
                this._ListenBacklog = value;
            }
        }

        private Socket _Socket;

        /// <summary>
        /// 指定网络地址以及通讯协议，初始化 <see cref="Sofire.DataComm.Net.SocketServer"/> 的新实例。
        /// </summary>
        /// <param name="mode">通讯协议的类型。</param>
        /// <param name="ip">网络 IP。</param>
        /// <param name="port">网络端口。</param>
        public SocketServer(ProtocolMode mode, string ip, int port)
            : this(new SocketInfo(mode, ip, port)) { }

        /// <summary>
        /// 指定网络端口以及通讯协议，默认 <see cref="System.Net.IPAddress.Loopback"/> 地址，初始化 <see cref="Sofire.DataComm.Net.SocketServer"/> 的新实例。
        /// </summary>
        /// <param name="mode">通讯协议的类型。</param>
        /// <param name="port">网络端口。</param>
        public SocketServer(ProtocolMode mode, int port)
            : this(new SocketInfo(mode, port)) { }

        /// <summary>
        /// 指定套接字信息，初始化 <see cref="Sofire.DataComm.Net.SocketServer"/> 的新实例。
        /// </summary>
        /// <param name="socketInfo">套接字的信息。</param>
        public SocketServer(SocketInfo socketInfo)
            : base(socketInfo)
        {
            BeginAcceptCallback = new AsyncCallback(OnBeginAccept);
        }

        /// <summary>
        /// 可靠的套接字 接收数据 或 发送数据 时抛出的异常。当发生异常后，<paramref name="fromSocket"/> 将停止接收。
        /// </summary>
        /// <param name="fromSocket">数据来源的 <see cref="System.Net.Sockets.Socket"/>。</param>
        /// <param name="exception">接收时抛出的异常。</param>
        protected override void OnSocketFaild(Socket fromSocket, Exception exception)
        {
            base.OnSocketFaild(fromSocket, exception);
            if(this.Rejected != null) this.Rejected(this, new SocketEventArgs(fromSocket));
        }

        /// <summary>
        /// 打开通讯时发生。
        /// </summary>
        protected override void OnOpen()
        {
            this._Socket = this._SocketInfo.CreateSocket();
            this._Socket.Bind(this._SocketInfo.EndPoint);
            this._Socket.Listen(_ListenBacklog);
            this.BeginAccept();
        }

        /// <summary>
        /// 关闭通讯时发生。
        /// </summary>
        protected override void OnClose()
        {
            this._Socket.Close();
            this._Socket = null;
        }

        private void OnBeginAccept(IAsyncResult ar)
        {
            if(!this.IsRunning) return;

            Socket acceptSocket = null;
            try
            {
                acceptSocket = this._Socket.EndAccept(ar);
            }
            catch(Exception ex)
            {
                this.AcceptedFaild(this, new ExceptionEventArgs(ex));
            }
            if(acceptSocket != null)
            {
                this.BeginReceive(acceptSocket);
                this.RaiseAccepted(acceptSocket);
            }
            // 继续侦听
            this.BeginAccept();
        }

        /// <summary>
        /// 开始异步接受一个传入的连接尝试。
        /// </summary>
        public virtual void BeginAccept()
        {
            if(!this.IsRunning) return;
            try
            {
                this._Socket.BeginAccept(this.BeginAcceptCallback, this._Socket);
            }
            catch(Exception ex)
            {
                this.SwitchState(ex);
            }
        }

        /// <summary>
        /// 接受一个传入的连接后发生。
        /// </summary>
        /// <param name="acceptSocket">一个 <see cref="System.Net.Sockets.Socket"/>，它处理与远程主机的通信。</param>
        protected virtual void RaiseAccepted(Socket acceptSocket)
        {
            if(this.Accepted != null) this.Accepted(this, new SocketEventArgs(acceptSocket));
        }
    }

    //public interface IMessageFormat
    //{
    //    byte[] Write(object data);
    //    object Read(byte[] bytes);
    //}

    //public abstract class ObjectSocket
    //{
    //    private IMessageFormat _Format;
    //    public IMessageFormat Format
    //    {
    //        get
    //        {
    //            return this._Format;
    //        }
    //    }

    //    private SocketBase _Owner;
    //    public SocketBase Owner
    //    {
    //        get
    //        {
    //            return this._Owner;
    //        }
    //    }

    //    public event ObjectSocketEventHandler WriteCompleted;
    //    public event ObjectSocketEventHandler ReadCompleted;


    //    public ObjectSocket(SocketBase owner, IMessageFormat format)
    //    {
    //        if(owner == null) throw new ArgumentNullException("owner");
    //        if(format == null) throw new ArgumentNullException("format");
    //        this._Format = format;
    //        this._Owner = owner;
    //        this._Owner.Received += new ReceivedEventHandler(Owner_Received);
    //    }

    //    protected virtual void Owner_Received(object sender, ReceivedEventArgs e)
    //    {
    //        this.OnReadCompleted(e.Socket, this._Format.Read(e.Data), e.Data);
    //    }

    //    protected virtual void OnReadCompleted(Socket fromSocket, object data, byte[] bytes)
    //    {
    //        if(this.WriteCompleted != null) this.WriteCompleted(this, new ObjectSocketEventArgs(fromSocket, data, bytes));
    //    }

    //    protected virtual void OnWriteCompleted(Socket toSocket, object data, byte[] bytes)
    //    {
    //        if(this.WriteCompleted != null) this.WriteCompleted(this, new ObjectSocketEventArgs(toSocket, data, bytes));
    //    }

    //    public virtual void Open()
    //    {
    //        this._Owner.Open();
    //    }

    //    public virtual void Close()
    //    {
    //        this._Owner.Close();
    //    }

    //}

    //public delegate void ObjectSocketEventHandler(object sender, ObjectSocketEventArgs e);
    //public class ObjectSocketEventArgs : EventArgs
    //{
    //    private Socket _Socket;
    //    public Socket Socket
    //    {
    //        get
    //        {
    //            return this._Socket;
    //        }
    //    }

    //    private object _Data;
    //    public object Data
    //    {
    //        get
    //        {
    //            return this._Data;
    //        }
    //    }

    //    private byte[] _Bytes;
    //    public byte[] Bytes
    //    {
    //        get
    //        {
    //            return this._Bytes;
    //        }
    //    }

    //    public ObjectSocketEventArgs(Socket socket, object data, byte[] bytes)
    //    {
    //        this._Socket = socket;
    //        this._Data = data;
    //        this._Bytes = bytes;
    //    }
    //}

    //public class ObjectSocketServer : ObjectSocket
    //{
    //    SocketServer _server;
    //    public ObjectSocketServer(SocketServer server, IMessageFormat format)
    //        : base(server, format)
    //    {
    //        this._server = server;
    //    }

    //    public void Write(Socket toSocket, object data)
    //    {
    //        var bytes = this.Format.Write(data);
    //        this._server.BeginSendTo(bytes, toSocket);
    //        this.OnWriteCompleted(toSocket, data, bytes);
    //    }
    //}

    //public class ObjectSocketClient : ObjectSocket
    //{
    //    SocketClient _client;
    //    public ObjectSocketClient(SocketClient server, IMessageFormat format)
    //        : base(server, format)
    //    {
    //        this._client = server;
    //    }

    //    public void Write(object data)
    //    {
    //        var bytes = this.Format.Write(data);
    //        this._client.BeginSend(bytes);
    //        this.OnWriteCompleted(this._client.Server, data, bytes);
    //    }
    //}

}
